package com.ry.es.eao;

import com.alibaba.fastjson.JSON;
import com.ry.es.client.EsClient;
import com.ry.es.model.EsModel;
import com.ry.es.model.EsPage;
import com.ry.es.query.EsQuery;
import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.delete.DeleteRequestBuilder;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.action.update.UpdateRequestBuilder;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

/**
 * Created by walker on 17-11-22.
 * es数据层访问对象
 */
public abstract class ModelEao<E extends EsModel>
{
    private EsClient esClient;
    private Class<E> modelClass;
    
    protected abstract String getIndex();
    protected abstract String getType();

    public ModelEao(){
        Type genType = getClass().getGenericSuperclass();
        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
        modelClass = (Class) params[0];
    }

    private IndexRequestBuilder createRequest(EsModel esModel){
        Map data = JSON.parseObject(JSON.toJSONString(esModel));
        System.out.println("---------------------insert:"+data);
        return esClient.getClient().prepareIndex(getIndex(), getType())
                //建议指定id
                .setId(esModel.getDocumentId())
                .setSource(data);
    }

    public boolean insert(EsModel esModel){
        IndexRequestBuilder requestBuilder = createRequest(esModel);
        requestBuilder.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);//立即更新
        IndexResponse response = requestBuilder.execute().actionGet();
        return response.isFragment();
    }

    public void batchInsert(List<EsModel> list){
        BulkRequestBuilder bulkRequestBuilder = esClient.getClient().prepareBulk();
        int index = 0;
        for(EsModel esModel : list){
            index++;
            bulkRequestBuilder.add(createRequest(esModel));
            if(index % 10000 == 0){
                bulkRequestBuilder.execute().actionGet();
                bulkRequestBuilder = esClient.getClient().prepareBulk();
            }
        }
        if(bulkRequestBuilder.numberOfActions() > 0){
            bulkRequestBuilder.execute().actionGet();
        }

    }

    public void update(String documentId, Map<String, Object> fields){
        UpdateRequestBuilder updateRequestBuilder = esClient.getClient().prepareUpdate(getIndex(), getType(), documentId);
        updateRequestBuilder.setDoc(fields);
        UpdateResponse response = updateRequestBuilder.execute().actionGet();
//        esClient.getClient().close();
    }

    public E get(String id){
        GetResponse response = esClient.getClient().prepareGet(getIndex(), getType(), id)
                .execute().actionGet();
        String json = response.getSourceAsString();
        return JSON.parseObject(json, modelClass);
    }

    public boolean delete(String id){
        DeleteRequestBuilder deleteRequestBuilder = esClient.getClient().prepareDelete(getIndex(), getType(), id);
        deleteRequestBuilder.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
        DeleteResponse response = deleteRequestBuilder
                .execute().actionGet();

        return response.isFragment();
    }

    public EsPage search(EsPage page, EsQuery... queries){
        SearchRequestBuilder requestBuilder = esClient.getClient().prepareSearch(getIndex()).setTypes(getType());//设置要查询的索引(index)

        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        for(EsQuery query : queries){
            boolQueryBuilder.must(query.toQuery());
        }
        requestBuilder.setQuery(boolQueryBuilder)
                .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
                .setFrom((page.getPageNo()-1)*page.getPageSize())
                .setSize(page.getPageSize())
                .setExplain(true);
        SearchResponse response = requestBuilder.execute().actionGet();
        SearchHits searchHits = response.getHits();

        for(SearchHit item : searchHits.getHits()){
            EsModel esModel = JSON.parseObject(item.getSourceAsString(), modelClass);
            esModel.setDocumentId(item.getId());
            page.add(esModel);
        }
        page.setTotal(searchHits.getTotalHits());
        esClient.getClient().close();
        return page;
    }

    public long count(EsQuery... queries){
        //官方建议用search代替count api
        EsPage page = new EsPage();
        page.setPageSize(0);
        search(page, queries);
        return page.getTotal();
    }

    public EsClient getEsClient()
    {
        return esClient;
    }

    public void setEsClient(EsClient esClient)
    {
        this.esClient = esClient;
    }
}
